<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8" />
    <title>自定义流程图</title>
    <style>
      ::-webkit-scrollbar {
        display: none;
      }
      html,
      body {
        overflow: hidden;
        margin: 0;
      }
    </style>
  </head>
  <body>
    <div id="mountNode"></div>
    <script>
      /*Fixing iframe window.innerHeight 0 issue in Safari*/ document.body.clientHeight;
    </script>
    <script src="../build/g6.js"></script>
    <script src="https://gw.alipayobjects.com/os/lib/dagre/0.8.4/dist/dagre.min.js"></script>
    <script>
      const colorMap = {
        凭证开立: '#72CC4A',
        凭证转让: '#1A91FF',
        凭证融资: '#FFAA15',
      };
      const data = {
        nodes: [
          {
            id: '1',
            label: '公司1',
          },
          {
            id: '2',
            label: '公司2',
          },
          {
            id: '3',
            label: '公司3',
          },
          {
            id: '4',
            label: '公司4',
          },
          {
            id: '5',
            label: '公司5',
          },
          {
            id: '6',
            label: '公司6',
          },
          {
            id: '7',
            label: '公司7',
          },
          {
            id: '8',
            label: '公司8',
          },
          {
            id: '9',
            label: '公司9',
          },
        ],
        edges: [
          {
            source: '1',
            target: '2',
            data: {
              type: '凭证开立',
              amount: '100,000,000,00 元',
              date: '2019-08-03',
            },
          },
          {
            source: '1',
            target: '3',
            data: {
              type: '凭证转让',
              amount: '100,000,000,00 元',
              date: '2019-08-03',
            },
          },
          {
            source: '2',
            target: '5',
            data: {
              type: '凭证开立',
              amount: '100,000,000,00 元',
              date: '2019-08-03',
            },
          },
          {
            source: '5',
            target: '6',
            data: {
              type: '凭证转让',
              amount: '100,000,000,00 元',
              date: '2019-08-03',
            },
          },
          {
            source: '3',
            target: '4',
            data: {
              type: '凭证融资',
              amount: '100,000,000,00 元',
              date: '2019-08-03',
            },
          },
          {
            source: '4',
            target: '7',
            data: {
              type: '凭证转让',
              amount: '100,000,000,00 元',
              date: '2019-08-03',
            },
          },
          {
            source: '1',
            target: '8',
            data: {
              type: '凭证转让',
              amount: '100,000,000,00 元',
              date: '2019-08-03',
            },
          },
          {
            source: '1',
            target: '9',
            data: {
              type: '凭证融资',
              amount: '100,000,000,00 元',
              date: '2019-08-03',
            },
          },
        ],
      };

      G6.registerNode(
        'round-rect',
        {
          drawShape: function drawShape(cfg, group) {
            const width = cfg.style.width;
            const stroke = cfg.style.stroke;
            const rect = group.addShape('rect', {
              attrs: {
                x: -width / 2,
                y: -15,
                width,
                height: 30,
                radius: 15,
                stroke,
                lineWidth: 1.2,
                fillOpacity: 1,
              },
            });
            const circleLeft = group.addShape('circle', {
              attrs: {
                x: -width / 2,
                y: 0,
                r: 3,
                fill: stroke,
              },
            });
            const circleRight = group.addShape('circle', {
              attrs: {
                x: width / 2,
                y: 0,
                r: 3,
                fill: stroke,
              },
            });
            return rect;
          },
          getAnchorPoints: function getAnchorPoints() {
            return [
              [0, 0.5],
              [1, 0.5],
            ];
          },
          update: function(cfg, item) {
            const group = item.getContainer();
            const children = group.get('children');
            const node = children[0];
            const circleLeft = children[1];
            const circleRight = children[2];

            const {
              style: { stroke },
              labelStyle,
            } = cfg;

            if (stroke) {
              node.attr('stroke', stroke);
              circleLeft.attr('fill', stroke);
              circleRight.attr('fill', stroke);
            }
          },
        },
        'single-shape',
      );

      G6.registerEdge('polyline', {
        itemType: 'edge',
        draw: function draw(cfg, group) {
          const startPoint = cfg.startPoint;
          const endPoint = cfg.endPoint;
          const centerPoint = {
            x: (startPoint.x + endPoint.x) / 2,
            y: (startPoint.y + endPoint.y) / 2,
          };

          const Ydiff = endPoint.y - startPoint.y;

          const slope = Ydiff !== 0 ? 500 / Math.abs(Ydiff) : 0;

          const cpOffset = 16;
          const offset = Ydiff < 0 ? cpOffset : -cpOffset;

          const line1EndPoint = {
            x: startPoint.x + slope,
            y: endPoint.y + offset,
          };
          const line2StartPoint = {
            x: line1EndPoint.x + cpOffset,
            y: endPoint.y,
          };

          // 控制点坐标
          const controlPoint = {
            x:
              ((line1EndPoint.x - startPoint.x) * (endPoint.y - startPoint.y)) /
                (line1EndPoint.y - startPoint.y) +
              startPoint.x,
            y: endPoint.y,
          };

          let path = [
            ['M', startPoint.x, startPoint.y],
            ['L', line1EndPoint.x, line1EndPoint.y],
            ['Q', controlPoint.x, controlPoint.y, line2StartPoint.x, line2StartPoint.y],
            ['L', endPoint.x, endPoint.y],
          ];

          if (Ydiff === 0) {
            path = [
              ['M', startPoint.x, startPoint.y],
              ['L', endPoint.x, endPoint.y],
            ];
          }

          const line = group.addShape('path', {
            attrs: {
              path,
              stroke: colorMap[cfg.data.type],
              lineWidth: 1.2,
              endArrow: false,
            },
          });

          const labelLeftOffset = 8;
          const labelTopOffset = 8;
          // amount
          const amount = group.addShape('text', {
            attrs: {
              text: cfg.data.amount,
              x: line2StartPoint.x + labelLeftOffset,
              y: endPoint.y - labelTopOffset - 2,
              fontSize: 14,
              textAlign: 'left',
              textBaseline: 'middle',
              fill: '#000000D9',
            },
          });
          // type
          const type = group.addShape('text', {
            attrs: {
              text: cfg.data.type,
              x: line2StartPoint.x + labelLeftOffset,
              y: endPoint.y - labelTopOffset - amount.getBBox().height - 2,
              fontSize: 10,
              textAlign: 'left',
              textBaseline: 'middle',
              fill: '#000000D9',
            },
          });
          // date
          const date = group.addShape('text', {
            attrs: {
              text: cfg.data.date,
              x: line2StartPoint.x + labelLeftOffset,
              y: endPoint.y + labelTopOffset + 4,
              fontSize: 12,
              fontWeight: 300,
              textAlign: 'left',
              textBaseline: 'middle',
              fill: '#000000D9',
            },
          });
          return line;
        },
      });

      const graph = new G6.Graph({
        container: 'mountNode',
        width: 1000,
        height: 800,
        layout: {
          type: 'dagre',
          rankdir: 'LR',
          nodesep: 30,
          ranksep: 100,
        },
        modes: {
          default: ['drag-canvas'],
        },
        defaultNode: {
          shape: 'round-rect',
          labelCfg: {
            style: {
              fill: '#000000A6',
              fontSize: 10,
            },
          },
          style: {
            stroke: '#72CC4A',
            width: 150,
          },
        },
        defaultEdge: {
          shape: 'polyline',
        },
      });

      graph.data(data);
      graph.render();

      const edges = graph.getEdges();
      edges.forEach(edge => {
        const line = edge.getKeyShape();
        const stroke = line.attr('stroke');
        const targetNode = edge.getTarget();
        targetNode.update({
          style: { stroke },
        });
      });
      graph.paint();
    </script>
  </body>
</html>
